package edu.ucdavis.gwt.gis.client.query;


import java.util.LinkedList;


import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Style.Cursor;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.LoadEvent;
import com.google.gwt.event.dom.client.MouseOutEvent;
import com.google.gwt.event.dom.client.MouseOutHandler;
import com.google.gwt.event.dom.client.MouseOverEvent;
import com.google.gwt.event.dom.client.MouseOverHandler;
import com.google.gwt.event.logical.shared.ResizeEvent;
import com.google.gwt.event.logical.shared.ResizeHandler;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Anchor;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.FocusPanel;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.PopupPanel;
import com.google.gwt.user.client.ui.RadioButton;
import com.google.gwt.user.client.ui.SimplePanel;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;

import edu.ucdavis.cstars.client.MapWidget;
import edu.ucdavis.cstars.client.event.MapZoomEndHandler;
import edu.ucdavis.cstars.client.geometry.Extent;
import edu.ucdavis.cstars.client.geometry.Point;
import edu.ucdavis.cstars.client.layers.LayerInfo;
import edu.ucdavis.gwt.gis.client.DataManager;
import edu.ucdavis.gwt.gis.client.Debugger;
import edu.ucdavis.gwt.gis.client.draw.DrawControl;
import edu.ucdavis.gwt.gis.client.extras.CloseButton;
import edu.ucdavis.gwt.gis.client.extras.ToolTip;
import edu.ucdavis.gwt.gis.client.layers.DataLayer;
import edu.ucdavis.gwt.gis.client.layers.DataLayerHandler;
import edu.ucdavis.gwt.gis.client.layers.MapServerDataLayer;
import edu.ucdavis.gwt.gis.client.layers.DataLayer.DataLayerLoadHandler;
import edu.ucdavis.gwt.gis.client.layers.DataLayer.DataLayerType;
import edu.ucdavis.gwt.gis.client.resources.GadgetResources;


public class QueryToolSettings extends PopupPanel {


	private static QueryToolSettingsUiBinder uiBinder = GWT.create(QueryToolSettingsUiBinder.class);
	interface QueryToolSettingsUiBinder extends UiBinder<Widget, QueryToolSettings> {}
	
	public static QueryToolSettings INSTANCE = new QueryToolSettings();

	@UiField FlowPanel layers;
	@UiField CheckBox highlight;
	@UiField HTML status;
	@UiField RadioButton pointQuery;
	@UiField RadioButton bboxQuery;
	@UiField CloseButton close;
	@UiField SimplePanel outerDisable;
	
	private Image toolbarIcon = new Image(GadgetResources.INSTANCE.querymapInactive());
	private LayerSelectPanel selectedPanel = null;
	//private SelectActionPopup selectActionPopup = new SelectActionPopup();
	private String DISABLED_TEXT = "The Query Tool is <b>Disabled</b>.";
	private String statusText = "";
	private HTML disable = new HTML(new Image(GadgetResources.INSTANCE.querymapInactive()).toString()+"&nbsp;&nbsp;Disable Query Tool", true);
	
	protected QueryToolSettings() {
		setWidget(uiBinder.createAndBindUi(this));
		getElement().getStyle().setZIndex(8000);
		setWidth("600px");
		
		Window.addResizeHandler(new ResizeHandler(){
			@Override
			public void onResize(ResizeEvent event) {
				if( isAttached() ) center();
			}
		});
		
		setAutoHideEnabled(true);
		setGlassEnabled(true);
		setStyleName("GwtGisPopup");
		setGlassStyleName("GwtGisPopup-glasspanel");
		close.addClickHandler(new ClickHandler(){
			@Override
			public void onClick(ClickEvent event) {
				hide();
			}
		});
		
		outerDisable.add(disable);
		disable.setStyleName("disableQueryButton");
		disable.addClickHandler(new ClickHandler(){
			@Override
			public void onClick(ClickEvent event) {
				disable();
			}
		});
		
		toolbarIcon.getElement().getStyle().setCursor(Cursor.POINTER);
		toolbarIcon.getElement().getStyle().setProperty("margin", "0 8px 0 7px");
		toolbarIcon.addClickHandler(new ClickHandler(){
			@Override
			public void onClick(ClickEvent event) {
	//			if( isActive() ) {
	//				selectActionPopup.show(toolbarIcon);
	//			} else {
					center();
	//			}
			}
		});
		toolbarIcon.addMouseOverHandler(new MouseOverHandler(){
			@Override
			public void onMouseOver(MouseOverEvent event) {
				ToolTip.INSTANCE.show(statusText, toolbarIcon);
			}
    	});
		toolbarIcon.addMouseOutHandler(new MouseOutHandler(){
			@Override
			public void onMouseOut(MouseOutEvent event) {
				ToolTip.INSTANCE.hide();
			}
    	});
		
		disable();
	}
	
	public void setMap(MapWidget map) {
		map.addZoomEndHandler(new MapZoomEndHandler() {
			@Override
			public void onZoomEnd(Extent extent, float zoomFactor,
					Point anchor, int level) {
				for( int i = 0; i < layers.getWidgetCount(); i++ ) {
					((LayerSelectPanel) layers.getWidget(i)).update();
				}
			}
		});
		
		LinkedList<DataLayer> datalayers = DataManager.INSTANCE.getDataLayers();
		for( DataLayer dl: datalayers ) {
			dl.addLoadHandler(new DataLayerLoadHandler(){
				@Override
				public void onDataLoaded(DataLayer dataLayer) {
					addDataLayer(dataLayer);
				}
			});
		}
		
		DataManager.INSTANCE.addDataLayerHandler(new DataLayerHandler() {
			@Override
			public void onDataLayerAdd(DataLayer dl) {
				addDataLayer(dl);
			}
			@Override
			public void onDataLayerRemove(DataLayer dl) {
				removeDataLayer(dl);
			}
			@Override
			public void onDataLayerUpdate(DataLayer dl) {
				updateDataLayer(dl);
			}
		});
	}
	
	public Image getToolbarIcon() {
		return toolbarIcon;
	}
	
	public boolean isActive() {
		if( selectedPanel != null ) {
			if( selectedPanel.hasVisibleAndSelectedSubLayer() ) return true;
		}
		return false;
	}
	
	public boolean isPointQuery() {
		return pointQuery.getValue();
	}
	
	public boolean isBboxQuery() {
		return bboxQuery.getValue();
	}

	private void setSelected(LayerSelectPanel lsp) {
		if( selectedPanel != null ) selectedPanel.unselect();
		selectedPanel = lsp;
		
		// make sure the draw tool is not enabled
		if( DrawControl.INSTANCE.isEnabled() ) {
			DrawControl.INSTANCE.enable(false);
		}
	}
	
	public boolean highlight() {
		return highlight.getValue();
	}
	
	public MapServerDataLayer getQueryLayer() {
		if( selectedPanel == null ) return null;
		return selectedPanel.getDataLayer();
	}
	
	public LinkedList<LayerInfo> getSelectedLayerInfos() {
		return selectedPanel.getSelectedLayerInfos();
	}
	
	private void addDataLayer(DataLayer dl) {
		if( dl.getType() == DataLayerType.MapServer ) {
			MapServerDataLayer msdl = (MapServerDataLayer) dl;
			if( !hasDataLayer(msdl) && !msdl.hasError() ) {
				layers.add(new LayerSelectPanel(msdl));
			}
		}
	}
	
	private void removeDataLayer(DataLayer dl) {
		for( int i = 0; i < layers.getWidgetCount(); i++ ) {
			LayerSelectPanel panel = (LayerSelectPanel) layers.getWidget(i);
			if( dl == panel.getDataLayer() ) {
				if( panel == selectedPanel ) disable();
				layers.remove(i);
				return;
			}
		}
	}
	
	private void updateDataLayer(DataLayer dl) {
		for( int i = 0; i < layers.getWidgetCount(); i++ ) {
			LayerSelectPanel panel = (LayerSelectPanel) layers.getWidget(i);
			if( dl == panel.getDataLayer() ) {
				panel.update();
				return;
			}
		}
	}
	
	private boolean hasDataLayer(MapServerDataLayer msdl) {
		for( int i = 0; i < layers.getWidgetCount(); i++ ) {
			if( ((LayerSelectPanel) layers.getWidget(i)).getDataLayer() == msdl ) 
				return true;
		}
		return false;
	}
	
	public void setDataLayer(MapServerDataLayer msdl) {
		for( int i = 0; i < layers.getWidgetCount(); i++ ) {
			if( ((LayerSelectPanel) layers.getWidget(i)).getDataLayer() == msdl ) 
				setSelected((LayerSelectPanel) layers.getWidget(i));
		}
	}

	public void disable() {
		toolbarIcon.setResource(GadgetResources.INSTANCE.querymapInactive());
		if( selectedPanel != null ) {
			selectedPanel.unselect();
			selectedPanel = null;
		}
		statusText = DISABLED_TEXT;
		status.setHTML(statusText);
		DataManager.INSTANCE.getMap().setMapCursor(Cursor.DEFAULT.getCssName());
		disable.setVisible(false);
	}
	
	
	public void selectServiceFromUrl(String url) {
		for( int i = 0; i < layers.getWidgetCount(); i++ ) {
			LayerSelectPanel lsp = (LayerSelectPanel) layers.getWidget(i);
			if( lsp.getDataLayer().getUrl().contentEquals(url) ){
				setSelected(lsp);
				lsp.select();
				lsp.updateStatus();
				highlight.setValue(true);
				return;
			}
		}
	};

	private class LayerSelectPanel extends Composite {
		private MapServerDataLayer dl;
		private CheckBox select = new CheckBox();
		
		private SimplePanel sublayersSp = new SimplePanel();
		private VerticalPanel sublayers = new VerticalPanel();
		
		private static final String INFO_DELIMITER = " - ";
		
		public LayerSelectPanel(MapServerDataLayer datalayer) {
			this.dl = datalayer;
			
			select.addClickHandler(new ClickHandler(){
				@Override
				public void onClick(ClickEvent event) {
					if( select.getValue() ) {
						setSelected(LayerSelectPanel.this);
						select();
						updateStatus();
					} else {
						disable();
					}
				}
			});

			for( int i = 0; i < dl.getLegendInfo().length(); i++ ) {
				LayerInfo info = dl.getLegendInfo().get(i);
				if( info.getLayerType().contentEquals("Feature Layer") ) {
					CheckBox cb = new CheckBox("<span style='color:#666666'>"+info.getId()+INFO_DELIMITER+info.getName()+"</span>", true);
					cb.getElement().getStyle().setMarginLeft(15, Unit.PX);
					cb.setValue(true);
					sublayers.add(cb);
				}
			}
			
			// there are no feature layers
			if( sublayers.getWidgetCount() == 0 ) {
				select.setEnabled(false);
			}
			
			dl.addLoadHandler(new DataLayerLoadHandler(){
				@Override
				public void onDataLoaded(DataLayer dataLayer) {
					update();
				}
			});
			
			FlowPanel panel = new FlowPanel();
			panel.add(select);
			sublayersSp.setStyleName("subLayerQueryPanel");
			panel.add(sublayersSp);
			sublayersSp.add(sublayers);
			initWidget(panel);
			panel.getElement().getStyle().setPadding(5, Unit.PX);
			unselect();
		}
		
		
		public LinkedList<LayerInfo> getSelectedLayerInfos() {
			LinkedList<LayerInfo> list = new LinkedList<LayerInfo>();
			for( int i = 0; i < sublayers.getWidgetCount(); i++ ) {
				CheckBox cb = (CheckBox) sublayers.getWidget(i);
				if( cb.getValue() ) {
					try {
						int id = Integer.valueOf(cb.getText().split(INFO_DELIMITER)[0]);
						LayerInfo info = getInfo(id);
						if( info != null ) list.add(info);
					} catch (Exception e) {}
				}
			}
			return list;
		}
		
		private LayerInfo getInfo(int id) {
			if( dl.getLegendInfo() != null ) {
				for( int i = 0; i < dl.getLegendInfo().length(); i++ ) {
					if( dl.getLegendInfo().get(i) != null ) {
						if( dl.getLegendInfo().get(i).getId() == id ) {
							return dl.getLegendInfo().get(i);
						}
					}
				}
			}
			return null;
		}
		
		private void select() {
			select.setValue(true);
			sublayersSp.setHeight(sublayers.getOffsetHeight()+"px");
		}
		
		public void unselect() {
			sublayersSp.setHeight("0px");
			select.setValue(false);
		}
		
		public MapServerDataLayer getDataLayer() {
			return dl;
		}
		
		private void updateStatus() {
			if( hasVisibleAndSelectedSubLayer() && select.getValue() ) {
				statusText = "<b>Active:</b> Querying layer "+dl.getLabel();
				status.setHTML(statusText);
				toolbarIcon.setResource(GadgetResources.INSTANCE.querymap());
				DataManager.INSTANCE.getMap().setMapCursor(Cursor.HELP.getCssName());
				disable.setVisible(true);
			} else if ( select.getValue() ) {
				statusText = "<b>Inactive:</b> Layer "+dl.getLabel()+" is select but has no visible layers at this scale.";
				status.setHTML(statusText);
				toolbarIcon.setResource(GadgetResources.INSTANCE.querymapInactive());
				DataManager.INSTANCE.getMap().setMapCursor(Cursor.DEFAULT.getCssName());
				disable.setVisible(true);
			}
		}
		
		public void update() {
			if( select.isEnabled() ) {
				select.setHTML(new Image(GadgetResources.INSTANCE.layers()).toString()+" <span style='font-size:16px;color:#333333'>"+dl.getLabel()+"</span>");
			} else {
				select.setHTML("<span style='font-size:16px;color:#888888'>"+dl.getLabel()+" contains no queryable layers.</span>");
			}
			
			double scale = Extent.getScale(DataManager.INSTANCE.getMap());
			for( int i = 0; i < sublayers.getWidgetCount(); i++ ) {
				CheckBox cb = (CheckBox) sublayers.getWidget(i);
				if( cb.getValue() ) {
					try {
						int id = Integer.valueOf(cb.getText().split(INFO_DELIMITER)[0]);
						LayerInfo info = getInfo(id);
						if( info != null ) {
							
							double minScale = info.getMinScale();
							double maxScale = info.getMaxScale();
							if( minScale < 0 ) minScale = 0;
							if( maxScale < 0 ) maxScale = 0;				
							if( ((minScale >= scale) && (scale >= maxScale)) || (minScale == 0 && maxScale == 0) ) {
								cb.setVisible(true);
							} else {
								cb.setVisible(false);
							}
						}
					} catch (Exception e) {}
				}
			}
			
			if( selectedPanel == this ) {
				sublayersSp.setHeight(sublayers.getOffsetHeight()+"px");
			}
			
			updateStatus();
		}
		
		private boolean hasVisibleAndSelectedSubLayer() {
			for( int i = 0; i < sublayers.getWidgetCount(); i++ ) {
				CheckBox cb = (CheckBox) sublayers.getWidget(i);
				if( cb.isVisible() && cb.getValue() ) return true;
			}
			return false;
		}
		
	}


}
